package com.zsc.common.web.util;

import com.zsc.common.web.result.Result;

import java.lang.management.ManagementFactory;
import java.net.NetworkInterface;
import java.util.Date;
import java.util.Enumeration;
import java.util.Random;

/**
 * CommonUtils.java是互动平台的共通工具类。
 *
 * @author jason
 * @version 1.0 2013-11-5
 */
public class CommonUtils {

    /**
     * 当前机器网卡MAC+进程号组合成16进制机器码字符串
     */
    private static final String hexMachineCode;

    static {
        // build a 2-byte machine piece based on NICs info
        int machinePiece;
        try {
            StringBuilder sb = new StringBuilder();
            Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
            while (e.hasMoreElements()) {
                NetworkInterface ni = e.nextElement();
                sb.append(ni.toString());
            }
            machinePiece = sb.toString().hashCode() << 16;
        } catch (Throwable e) {
            // exception sometimes happens with IBM JVM, use random
            machinePiece = (new Random().nextInt()) << 16;
        }

        // add a 2 byte process piece. It must represent not only the JVM but the class loader.
        // Since static var belong to class loader there could be collisions otherwise
        int processPiece;
        int processId = 0;
        try {
            processId = ManagementFactory.getRuntimeMXBean().getName().hashCode();
        } catch (Throwable t) {
            // exception sometimes happens with IBM JVM, use random
            processId = new Random().nextInt();
        }
        ClassLoader loader = CommonUtils.class.getClassLoader();
        int loaderId = loader != null ? System.identityHashCode(loader) : 0;
        StringBuilder sb = new StringBuilder();
        sb.append(Integer.toHexString(processId));
        sb.append(Integer.toHexString(loaderId));
        processPiece = sb.toString().hashCode() & 0xFFFF;

        int machineCode = machinePiece | processPiece;
        hexMachineCode = Integer.toHexString(machineCode).toLowerCase();
    }

    /**
     * 根据当前汇率，把虚拟货币金额反算出实际货币金额。
     *
     * @param exchangeRate 当前汇率
     * @param costAmount   虚拟货币金额
     * @return 实际货币金额
     */
    public static Integer inverseToMoney(Integer exchangeRate, Integer costAmount) {
        // 由于数据库里保存的汇率是实际汇率*100的值，那么实际结算时需要除以100。
        double doubleExchangeRate = new Double(exchangeRate) / 100;
        // 实际金额(单位：分) = 当前消费财豆 / 当前汇率
        double money = costAmount / doubleExchangeRate;
        return Double.valueOf(money).intValue();
    }

    /**
     * 获取一个新的用户IM账户ID。
     */
    public static String getNewUserImId() {
        // 用户IMID = u + 机器码 + 时间戳
        StringBuilder userImId = new StringBuilder("u");
        userImId.append(hexMachineCode);
        String hexCurrentTime = Long.toHexString(System.currentTimeMillis()).toLowerCase();
        userImId.append(hexCurrentTime);
        return userImId.toString();
    }

    /**
     * 认证API访问权限。
     *
     * @param actualSign 实际安全签名
     * @param deadline   过期时间，UNIX时间戳(十进制)，即从1970年1月1日（UTC/GMT的午夜）开始所经过的秒数。
     * @param apiKey     互动平台API鉴权Key
     * @param result     认证结果对象
     * @return true:认证通过 false:认证不通过
     */
    public static boolean authApiAccess(String actualSign, Long deadline, String apiKey, Result result) {
        // 检查是否访问过期了
        if (deadline == null || deadline < (System.currentTimeMillis() / 1000)) {
            result.setCode(CodeEnum.code990507.getCode());
            result.setMsg(CodeEnum.code990507.getDesc());
            return false;
        }
        // 检查签名是否有效
        String expectedSign = MD5Util.md5(apiKey + deadline).toLowerCase();
        if (expectedSign.equals(actualSign)) {
            return true;
        } else {
            result.setCode(CodeEnum.code990508.getCode());
            result.setMsg(CodeEnum.code990508.getDesc());
            return false;
        }
    }

    /**
     * 获取当前机器网卡MAC+进程号组合成16进制机器码字符串。
     */
    public static String getHexMachineCode() {
        return hexMachineCode;
    }

    /**
     * 获取全局唯一性序列号。
     */
    public static String getSerialNumber() {
        return DateUtils.formatByTimestampMillis(new Date()) + hexMachineCode;
    }
}
